package com.qf.listener;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.config.DelayedConfig;
import com.qf.config.RabbitMQConfig;
import com.qf.constant.CacheConstants;
import com.qf.constant.RabbitMQConstants;
import com.qf.feign.CacheFeign;
import com.qf.model.StandardReport;
import com.qf.model.StandardSubmit;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 接口模块  监听 RabbitMQ
 *
 * @author lixu
 */
@Component
public class RabbitMQListener {

    @Autowired
    private ObjectMapper objectMapper;//不用同学去创建了   启动器
    @Autowired
    private RestTemplate restTemplate;//
    @Autowired
    private CacheFeign cacheFeign;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    //状态报告发送次数和时间: 1,2,3,4,5
    //立即推送,10s之后， 30s之后，1min， 5min
    private Integer[] sendTTL = {0, 10000, 30000, 60000, 300000};


    /**
     * 第二次开始监听时候 就延迟消息
     * 第三次开始监听时候 就延迟消息
     * 第四次开始监听时候 就延迟消息
     * 第五次开始监听时候 就延迟消息
     */
    @RabbitListener(queues = DelayedConfig.DELAYED_QUEUE)
    public void receiverDelayMessageByStandardReport(StandardReport standardReport, Message message, Channel channel) {
        try {

            if(standardReport.getSendCount() > 3){
                System.out.println("不能再发送了/已经发5次了");
                //打印日志
                //转人工处理
                //手动应答
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                return;
            }
            //记录当前是第一次发送状态报告  至少是
            standardReport.setSendCount(standardReport.getSendCount()+1);
            System.out.println("延迟消息：第" + standardReport.getSendCount() + "次发送消息");
            sendReport(standardReport);
            //手动应答
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 监听 RabbitMQ中状态报告
     * <p>
     * 队列名称
     * public final static String TOPIC_PUSH_SMS_REPORT = "push_sms_report_topic";
     * //交换机名称   主题交接机
     * public final static String TOPIC_PUSH_SMS_REPORT = "push_sms_report_topic_exchange";
     * //routingkey  #
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = RabbitMQConstants.TOPIC_PUSH_SMS_REPORT, durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = RabbitMQConstants.TOPIC_PUSH_SMS_REPORT + "_exchange", type = "topic"),
            key = "#"
    ))
    public void receiverStandardReport(StandardReport standardReport, Message message, Channel channel) {
        try {
            System.out.println("接收到的对象是：" + objectMapper.writeValueAsString(standardReport));

            //当前客户的缓存Key
            String cacheKey = CacheConstants.CACHE_PREFIX_CLIENT + standardReport.getClientID();
            Map map = cacheFeign.hMGet(cacheKey);
            //1:判断用户是否需要推送报告
            Object isreturnstatus = map.get("isreturnstatus");
            if ("1".equals(isreturnstatus)) {
                //2:需要   推送报告的URL是多少
                String receivestatusurl = (String) map.get("receivestatusurl");
                if (null != receivestatusurl) {

                    System.out.println("正常消息:第一次发送消息");
                    standardReport.setReceiveStatusUrl(receivestatusurl);
                    //3、开始推送报告
                    String result = sendReport(standardReport);
                    if(null != result){
                        //Http请求成功  不能保证是success
                        isSuccess(standardReport,result);
                    }
                }
            }
            //不需要 推送
            //手动应答
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 判断 返回值是否是success 七个字符
     * @param result
     */
    private void isSuccess(StandardReport standardReport,String result) {
        if(!"success".equalsIgnoreCase(result)){
            //发送延迟消息
            rabbitTemplate.convertAndSend(DelayedConfig.DELAYED_EXCHANGE,
                    DelayedConfig.DELAYED_ROUTING_KEY, standardReport,
                    message -> {
                        //设置延迟消息
                        message.getMessageProperties().setDelay(sendTTL[standardReport.getSendCount()]);
                        return message;
                    });
        }
    }

    /**
     * 开始推送报告
     */
    private String sendReport(StandardReport standardReport) {
        String result = null;
        try {
            //请求头
            MultiValueMap<String, String> headers = new HttpHeaders();
            //发送的请求体是什么格式的数据  JSON串
            headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
            //add:请求头一个一个的添加
            //put:请求头一加加一堆
            //请求体
            HttpEntity httpEntity = new HttpEntity(standardReport, headers);
            //Http 协议  POST请求
            //参数1：url
            //参数2：请求体
            //参数3：响应返回值的类型  success 七个字符大小写无所谓
            result = restTemplate.postForObject(standardReport.getReceiveStatusUrl(),
                    httpEntity, String.class);
        } catch (Exception e) {
            //e.printStackTrace();
            //发送延迟消息
            rabbitTemplate.convertAndSend(DelayedConfig.DELAYED_EXCHANGE,
                    DelayedConfig.DELAYED_ROUTING_KEY, standardReport,
                    message -> {
                        //设置延迟消息
                        message.getMessageProperties().setDelay(sendTTL[standardReport.getSendCount()]);
                        return message;
                    });
            //本次发送消费失败 返回值 null
            return result;
        }
        //没有出现异常 返回值为有的
        return result;
    }


    /**
     * 基于死信的 延迟消息
     */
    @RabbitListener(queues = RabbitMQConfig.NORMAL_QUEUE)
    public void receiverMessageByDeadLetter(Message message, String msg, Channel channel) {
        try {
            System.out.println("接收基于死信的：" + msg + ":" + new Date());
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 基于插件 延迟消息
     */
    @RabbitListener(queues = RabbitMQConfig.DELAY_QUEUE)
    public void receiverMessageByDelayed(Message message, String msg, Channel channel) {
        try {
            System.out.println("接收基于插件的：" + msg + ":" + new Date());
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
